package org.bdware.doip.examples;


import org.apache.log4j.Logger;
import org.bdware.doip.core.doipMessage.DoipMessage;
import org.bdware.doip.core.doipMessage.DoipResponseCode;
import org.bdware.doip.core.model.digitalObject.DOList;
import org.bdware.doip.core.model.digitalObject.DigitalObject;
import org.bdware.doip.core.model.digitalObject.DoType;
import org.bdware.doip.core.model.digitalObject.Element;
import org.bdware.doip.endpoint.doipServer.DoipServiceInfo;
import org.bdware.doip.endpoint.doipServer.RepositoryHandlerBase;
import org.bdware.doip.implementation.DoStorage;
import org.bdware.irp.client.GlobalIrpClient;
import org.bdware.irp.client.IrpClient;
import org.bdware.irp.stateinfo.DoStateInfo;

import java.util.List;

public class SimpleRepositoryHandler extends RepositoryHandlerBase {

    Logger logger = Logger.getLogger(SimpleRepositoryHandler.class);
    DoStorage store;


    public SimpleRepositoryHandler(DoipServiceInfo info, DoStorage s){
        super(info);
        serviceInfo = info;
        store = s;
    }


    @Override
    public DoipMessage handleHello(DoipMessage request) {
        return replyDoipServiceInfo(request);
    }

    @Override
    public DoipMessage handleListOps(DoipMessage request) {
        return replyAllOperations(request);
    }

    @Override
    public DoipMessage handleCreate(DoipMessage request) {
        try {
            if (!request.header.parameters.id.equals(serviceInfo.id)) {
                return replyStringWithStatus(request, "Wrong operation targetID, should be: " + serviceInfo.id, DoipResponseCode.Invalid);
            }
            DigitalObject digitalObject = request.body.getDataAsDigitalObject();
            if(digitalObject.id != null && !digitalObject.id.equals("")){
                DigitalObject ret = store.getDoByID(digitalObject.id);
                if (ret != null) {
                    return replyStringWithStatus(request, "Failed: the data of this DO is already existed.", DoipResponseCode.DoAlreadyExist);
                }
            }
            if(digitalObject.type == DoType.DOList){
                DOList doList = DOList.fromDigitalObject(digitalObject);
                List<DigitalObject> dos = doList.getDOList();
                IrpClient irpClient = GlobalIrpClient.getGlobalClient();
                DoStateInfo doHR = new DoStateInfo(serviceInfo.owner,serviceInfo.id);
                List<String> ids = irpClient.batchRegister(doHR, 1+dos.size());
                doList = new DOList(ids.get(0));
                for(int i=0;i<dos.size();i++){
                    dos.get(i).id = ids.get(i+1);
                    store.storeDo(dos.get(i));
                    doList.addDO(dos.get(i));
                }
                //clean the elements data
                store.storeDo(doList);
                for (Element e : doList.elements) {
                    e.excludeData();
                }

                return replyDO(request,doList);
            }
            if(digitalObject.id == null || digitalObject.id.equals("")){
                logger.debug("register DO for user");
                IrpClient irpClient = GlobalIrpClient.getGlobalClient();
                DoStateInfo doHR = new DoStateInfo(serviceInfo.owner,serviceInfo.id);
                digitalObject.id = irpClient.register(doHR);
            }
            logger.debug("Message body length: " + request.body.getLength());
            logger.info("create DO identifier : " + digitalObject.id);
            store.storeDo(digitalObject);
            if (digitalObject.elements != null)
                for (Element e : digitalObject.elements) {
                    e.excludeData();
                }
            return replyDO(request,digitalObject);
        } catch (Exception e) {
            e.printStackTrace();
            return replyStringWithStatus(request, "Server Exception: " + e.getMessage(), DoipResponseCode.MoreThanOneErrors);
        }
    }

    @Override
    public DoipMessage handleUpdate(DoipMessage request) {
        try {
            DigitalObject digitalObject = request.body.getDataAsDigitalObject();
            if (!request.header.parameters.id.equals(digitalObject.id)) {
                return replyStringWithStatus(request, "Invalid request: different identifiers in DO and message header.", DoipResponseCode.Invalid);
            }
            DigitalObject ret = store.getDoByID(digitalObject.id);
            if (ret == null) {
                return replyStringWithStatus(request, "Failed: DO is not existed.", DoipResponseCode.DoNotFound);
            }
            store.updateDo(digitalObject);
            if (digitalObject.elements != null)
                for (Element e : digitalObject.elements) {
                    e.excludeData();
                }
            return replyDO(request,digitalObject);
        } catch (Exception e) {
            e.printStackTrace();
            return replyStringWithStatus(request, "Server Exception: " + e.getMessage(), DoipResponseCode.MoreThanOneErrors);
        }
    }

    @Override
    public DoipMessage handleDelete(DoipMessage request) {
        try {
            DigitalObject ret = store.getDoByID(request.header.parameters.id);
            if (ret == null) {
                return replyStringWithStatus(request, "Failed: DO is not existed.", DoipResponseCode.DoNotFound);
            }
            store.deleteDoByID(request.header.parameters.id);
            return replyNull(request);
        }catch (Exception e){
            e.printStackTrace();
            return replyStringWithStatus(request, "Server Exception: " + e.getMessage(), DoipResponseCode.MoreThanOneErrors);
        }
    }

    @Override
    public DoipMessage handleRetrieve(DoipMessage request) {
        try {
            DigitalObject ret = store.getDoByID(request.header.parameters.id);
            if (ret == null) {
                return replyStringWithStatus(request, "Failed: DO is not existed.", DoipResponseCode.DoNotFound);
            }
            if(ret.elements!= null){
                //如果是获取element
                if (request.header.parameters.attributes != null && request.header.parameters.attributes.has("element")) {
                    for (Element e : ret.elements) {
                        if (e.id.equals(request.header.parameters.attributes.get("element").getAsString())) {
                            return replyString(request, e.getData() == null ? "" : new String(e.getData()));
                        }
                    }
                    return replyStringWithStatus(request,
                            "element not found: " + request.header.parameters.attributes.get("element"),
                            DoipResponseCode.DoNotFound);
                }
                //不需要获取Elementdata
                if (request.header.parameters.attributes == null ||
                        !request.header.parameters.attributes.has("includeElementData")) {
                    logger.debug("clean element data");
                    for (Element e : ret.elements) {
                        e.excludeData();
                    }
                }
            }
            return replyDO(request,ret);
        }catch (Exception e){
            e.printStackTrace();
            return replyStringWithStatus(request, "Server Exception: " + e.getMessage(), DoipResponseCode.MoreThanOneErrors);
        }
    }

}
